home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / fax / src / faxd / Class1Send.c++ < prev    next >
C/C++ Source or Header  |  1994-08-01  |  21KB  |  726 lines

  1. /*    $Header: /usr/people/sam/fax/faxd/RCS/Class1Send.c++,v 1.53 1994/04/08 20:28:19 sam Rel $ */
  2. /*
  3.  * Copyright (c) 1990, 1991, 1992, 1993, 1994 Sam Leffler
  4.  * Copyright (c) 1991, 1992, 1993, 1994 Silicon Graphics, Inc.
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software and 
  7.  * its documentation for any purpose is hereby granted without fee, provided
  8.  * that (i) the above copyright notices and this permission notice appear in
  9.  * all copies of the software and related documentation, and (ii) the names of
  10.  * Sam Leffler and Silicon Graphics may not be used in any advertising or
  11.  * publicity relating to the software without the specific, prior written
  12.  * permission of Sam Leffler and Silicon Graphics.
  13.  * 
  14.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  15.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  16.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  17.  * 
  18.  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  19.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  20.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  21.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  22.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  23.  * OF THIS SOFTWARE.
  24.  */
  25.  
  26. /*
  27.  * EIA/TIA-578 (Class 1) Modem Driver.
  28.  *
  29.  * Send protocol.
  30.  */
  31. #include <stdio.h>
  32. #include <time.h>
  33. #include "Class1.h"
  34. #include "ModemConfig.h"
  35. #include "HDLCFrame.h"
  36. #include "t.30.h"
  37.  
  38. /*
  39.  * Dial the phone number.  We override this method
  40.  * so that we can force the terminal into a known
  41.  * flow control state.
  42.  */
  43. CallStatus
  44. Class1Modem::dial(const char* number)
  45. {
  46.     if (flowControl == FLOW_XONXOFF)
  47.     setXONXOFF(FLOW_NONE, FLOW_NONE, ACT_FLUSH);
  48.     return FaxModem::dial(number);
  49. }
  50.  
  51. /*
  52.  * Wait-for and process a dial command response.
  53.  */
  54. CallStatus
  55. Class1Modem::dialResponse()
  56. {
  57.     int ntrys = 0;
  58.     for (;;) {
  59.     switch (atResponse(rbuf, conf.dialResponseTimeout)) {
  60.     case AT_BUSY:    return (BUSY);
  61.     case AT_NODIALTONE:    return (NODIALTONE);
  62.     case AT_NOANSWER:    return (NOANSWER);
  63.     case AT_ERROR:        return (ERROR);
  64.     case AT_CONNECT:    return (OK);
  65.     case AT_OK:        return (NOCARRIER);
  66.     case AT_NOCARRIER:    return (NOCARRIER);
  67.     default:        return (FAILURE);
  68.     case AT_FCERROR:
  69.         /*
  70.          * Some modems that support adaptive-answer assert a data
  71.          * carrier first and then fall back to answering as a fax
  72.          * modem.  For these modems we'll get an initial +FCERROR
  73.          * (wrong carrier) result that we ignore.  We actually
  74.          * accept three of these in case the modem switches carriers
  75.          * several times (haven't yet encountered anyone that does).
  76.          */
  77.         if (++ntrys == 3)
  78.         return (FAILURE);
  79.         break;
  80.     }
  81.     }
  82. }
  83.  
  84. void
  85. Class1Modem::sendBegin()
  86. {
  87.     setInputBuffering(FALSE);
  88.     // polling accounting?
  89.     params.br = (u_int) -1;            // force initial training
  90. }
  91.  
  92. /*
  93.  * Get the initial DIS command.
  94.  */
  95. fxBool
  96. Class1Modem::getPrologue(Class2Params& params, u_int& nsf, fxStr& csi, fxBool& hasDoc)
  97. {
  98.     u_int t1 = howmany(conf.t1Timer, 1000);    // T1 timer in seconds
  99.     time_t start = time(0);
  100.     HDLCFrame frame(conf.class1FrameOverhead);
  101.  
  102.     /*
  103.      * Wait up to T1 for an initial frame.
  104.      */
  105.     startTimeout(conf.t4Timer);
  106.     if (!recvRawFrame(frame)) {
  107.     do {
  108.         if (time(0)-start >= t1)
  109.         return (FALSE);
  110.     } while (!recvFrame(frame, conf.t4Timer));
  111.     }
  112.     /*
  113.      * An HDLC frame was received; process any
  114.      * optional frames that precede the DIS.
  115.      */
  116.     csi = "";
  117.     nsf = 0;
  118.     do {
  119.     switch (frame.getFCF()) {
  120.     case FCF_NSF:
  121.         nsf = frame.getDataWord();
  122.         break;
  123.     case FCF_CSI:
  124.         decodeTSI(csi, frame);
  125.         recvCSI(csi);
  126.         break;
  127.     case FCF_DIS:
  128.         dis = frame.getDIS();
  129.         params.setFromDIS(dis, frame.getXINFO());
  130.         curcap = NULL;        // force setup
  131.         break;
  132.     }
  133.     } while (frame.moreFrames() && recvFrame(frame, conf.t4Timer));
  134.     hasDoc = (dis & DIS_T4XMTR) != 0;        // documents to poll
  135.     /*
  136.      * NB: we don't handle DTC, only DIS.
  137.      */
  138.     return (frame.isOK() && frame.getFCF() == FCF_DIS && (dis&DIS_T4RCVR) != 0);
  139. }
  140.  
  141. /*
  142.  * Setup file-independent parameters prior
  143.  * to entering Phase B of the send protocol.
  144.  */
  145. void
  146. Class1Modem::sendSetupPhaseB()
  147. {
  148. }
  149.  
  150. const u_int Class1Modem::modemPFMCodes[8] = {
  151.     FCF_MPS,        // PPM_MPS
  152.     FCF_EOM,        // PPM_EOM
  153.     FCF_EOP,        // PPM_EOP
  154.     FCF_EOP,        // 3 ??? XXX
  155.     FCF_PRI_MPS,    // PPM_PRI_MPS
  156.     FCF_PRI_EOM,    // PPM_PRI_EOM
  157.     FCF_PRI_EOP,    // PPM_PRI_EOP
  158.     FCF_EOP,        // 7 ??? XXX
  159. };
  160.  
  161. /*
  162.  * Send the specified document using the supplied
  163.  * parameters.  The pph is the post-page-handling
  164.  * indicators calculated prior to intiating the call.
  165.  */
  166. fxBool
  167. Class1Modem::sendPhaseB(TIFF* tif, Class2Params& next, FaxMachineInfo& info,
  168.     fxStr& pph, fxStr& emsg)
  169. {
  170.     int ntrys = 0;            // # retraining/command repeats
  171.     fxBool morePages = TRUE;        // more pages still to send
  172.     fxBool transferOK = TRUE;
  173.     HDLCFrame frame(conf.class1FrameOverhead);
  174.  
  175.     do {
  176.     transferOK = !abortRequested();
  177.     if (!transferOK)
  178.         break;
  179.     /*
  180.      * Check the next page to see if the transfer
  181.      * characteristics change.  If so, update the
  182.      * T.30 session parameters and do training.
  183.      * Note that since the initial parameters are
  184.      * setup to be "undefined", training will be
  185.      * sent for the first page after receiving the
  186.      * DIS frame.
  187.      */
  188.     if (params != next) {
  189.         transferOK = sendTraining(next, 3, emsg);
  190.         if (!transferOK)
  191.         break;
  192.         params = next;
  193.     }
  194.     /*
  195.      * Transmit the facsimile message/Phase C.
  196.      */
  197.     transferOK = sendPage(tif, params, emsg);
  198.     if (!transferOK)
  199.         break;            // a problem, disconnect
  200.     /*
  201.      * Everything went ok, look for the next page to send.
  202.      */
  203.     morePages = !TIFFLastDirectory(tif);
  204.     int cmd;
  205.     // XXX check pph length
  206.     switch (pph[0]) {
  207.     default:
  208.         morePages = FALSE;
  209.         emsg = "Unknown post-page-handling indicator \"" | pph | "\"";
  210.         /* fall thru... */
  211.     case 'P': cmd = FCF_EOP; break;
  212.     case 'M': cmd = FCF_EOM; break;
  213.     case 'S': cmd = FCF_MPS; break;
  214.     }
  215.     int ncrp = 0;
  216.     /*
  217.      * Delay before switching to the low speed carrier to
  218.      * send the post-page-message frame.  We follow the spec
  219.      * in delaying 75ms before switching carriers, except
  220.      * when at EOP in which case we delay longer because,
  221.      * empirically, some machines need more time.  Beware
  222.      * that, reportedly, lengthening this delay too much can
  223.      * permit echo suppressors to kick in with bad results.
  224.      *
  225.      * NB: We do not use +FTS because many modems are slow
  226.      *     to send the OK result and so using pause is more
  227.      *     accurate.
  228.      */
  229.     pause(cmd == FCF_MPS ? conf.class1SendPPMDelay : 95);
  230.     do {
  231.         /*
  232.          * Send post-page message and get response.
  233.          */
  234.         transferOK = sendPPM(cmd, frame, emsg);
  235.         if (!transferOK)
  236.         break;
  237.         u_int ppr = frame.getFCF();
  238.         tracePPR("SEND recv", ppr);
  239.         switch (ppr) {
  240.         case FCF_RTP|FCF_RCVR:    // ack, continue after retraining
  241.         params.br = (u_int) -1;    // force retraining above
  242.         /* fall thru... */
  243.         case FCF_MCF|FCF_RCVR:    // ack confirmation
  244.         case FCF_PIP|FCF_RCVR:    // ack, w/ operator intervention
  245.         countPage();        // update server
  246.         pph.remove(0);        // discard post-page-handling
  247.         ntrys = 0;
  248.         if (morePages && transferOK)
  249.             transferOK = (TIFFReadDirectory(tif) &&
  250.             sendSetupParams(tif, next, info, emsg));
  251.         break;
  252.         case FCF_DCN|FCF_RCVR:    // disconnect, abort
  253.         emsg = "Remote fax disconnected prematurely";
  254.         transferOK = FALSE;
  255.         break;
  256.         case FCF_RTN|FCF_RCVR:    // nak, retry after retraining
  257.         if ((++ntrys % 2) == 0) {
  258.             /*
  259.              * Drop to a lower signalling rate and retry.
  260.              */
  261.             if (params.br == BR_2400) {
  262.             emsg = "Unable to transmit page"
  263.                    " (NAK at all possible signalling rates)";
  264.             transferOK = FALSE;
  265.             break;
  266.             }
  267.             --params.br;
  268.             curcap = NULL;    // force sendTraining to reselect
  269.         }
  270.         if (transferOK = sendTraining(params, 3, emsg)) {
  271.             morePages = TRUE;    // force continuation
  272.             next = params;    // avoid retraining above
  273.         }
  274.         break;
  275.         case FCF_PIN|FCF_RCVR:    // nak, retry w/ operator intervention
  276.         emsg = "Unable to transmit page"
  277.                " (NAK with operator intervention)";
  278.         transferOK = FALSE;
  279.         break;
  280.         case FCF_CRP|FCF_RCVR:
  281.         break;
  282.         default:            // unexpected abort
  283.         emsg = "Fax protocol error (unknown frame received)";
  284.         transferOK = FALSE;
  285.         break;
  286.         }
  287.     } while (frame.getFCF() == FCF_CRP && ++ncrp < 3);
  288.     if (ncrp == 3) {
  289.         emsg = "Fax protocol error (command repeated 3 times)";
  290.         transferOK = FALSE;
  291.     }
  292.     } while (transferOK && morePages);
  293.     return (transferOK);
  294. }
  295.  
  296. /*
  297.  * Send ms's worth of zero's at the current signalling rate.
  298.  * Note that we send real zero data here rather than using
  299.  * the Class 1 modem facility to do zero fill.
  300.  */
  301. fxBool
  302. Class1Modem::sendTCF(const Class2Params& params, u_int ms)
  303. {
  304.     u_int tcfLen = params.transferSize(ms);
  305.     u_char* tcf = new u_char[tcfLen];
  306.     memset(tcf, 0, tcfLen);
  307.     fxBool ok = transmitData(curcap->value, tcf, tcfLen, frameRev, TRUE);
  308.     delete tcf;
  309.     return ok;
  310. }
  311.  
  312. /*
  313.  * Send the training prologue frames; TSI and DCS.
  314.  */
  315. fxBool
  316. Class1Modem::sendPrologue(u_int dcs, const fxStr& tsi)
  317. {
  318.     if (transmitFrame(FCF_TSI|FCF_SNDR, tsi, FALSE)) {
  319.     startTimeout(2550);            // 3.0 - 15% = 2.55 secs
  320.     fxBool frameSent = sendFrame(FCF_DCS|FCF_SNDR, dcs);
  321.     stopTimeout("sending DCS frame");
  322.     return (frameSent);
  323.     } else
  324.     return (FALSE);
  325. }
  326.  
  327. /*
  328.  * Return whether or not the previously received DIS indicates
  329.  * the remote side is capable of the T.30 DCS signalling rate.
  330.  */
  331. static fxBool
  332. isCapable(u_int sr, u_int dis)
  333. {
  334.     dis = (dis & DIS_SIGRATE) >> 10;
  335.     switch (sr) {
  336.     case DCSSIGRATE_2400V27:
  337.     case DCSSIGRATE_4800V27:
  338.     return ((dis & (DISSIGRATE_V27|DISSIGRATE_V27FB)) != 0);
  339.     case DCSSIGRATE_9600V29:
  340.     case DCSSIGRATE_7200V29:
  341.     return ((dis & DISSIGRATE_V29) != 0);
  342.     case DCSSIGRATE_14400V33:
  343.     case DCSSIGRATE_12000V33:
  344.     if (dis == 0xE)
  345.         return (TRUE);
  346.     /* fall thru... */
  347.     case DCSSIGRATE_14400V17:
  348.     case DCSSIGRATE_12000V17:
  349.     case DCSSIGRATE_9600V17:
  350.     case DCSSIGRATE_7200V17:
  351.     return (dis == 0xD);
  352.     }
  353.     return (FALSE);
  354. }
  355.  
  356. /*
  357.  * Send capabilities and do training.
  358.  */
  359. fxBool
  360. Class1Modem::sendTraining(Class2Params& params, int tries, fxStr& emsg)
  361. {
  362.     if (tries == 0) {
  363.     emsg = "DIS/DTC received 3 times; DCS not recognized";
  364.     return (FALSE);
  365.     }
  366.     u_int dcs = params.getDCS();        // NB: 32-bit DCS
  367.     if (!curcap) {
  368.     /*
  369.      * Select Class 1 capability: use params.br to hunt
  370.      * for the best signalling scheme acceptable to both
  371.      * local and remote (based on received DIS and modem
  372.      * capabilities gleaned at modem setup time).
  373.      */
  374.     params.br++;                // XXX can go out of range
  375.     if (!dropToNextBR(params))
  376.         goto failed;
  377.     }
  378.     do {
  379.     /*
  380.      * Override the Class 2 parameter bit rate
  381.      * capability and use the signalling rate
  382.      * calculated from the modem's capabilities
  383.      * and the received DIS.  This is because
  384.      * the Class 2 state does not include the
  385.      * modulation technique (v.27, v.29, v.17, v.33).
  386.      */
  387.     params.br = curcap->br;
  388.     // NB: <<8's are because dcs is in 32-bit format
  389.     dcs = (dcs &~ (DCS_SIGRATE<<8)) | (curcap->sr<<8);
  390.     int t = 2;
  391.     do {
  392.         protoTrace("SEND training at %s %s",
  393.         modulationNames[curcap->mod],
  394.         Class2Params::bitRateNames[curcap->br]);
  395.         if (!sendPrologue(dcs, lid)) {
  396.         if (abortRequested())
  397.             goto done;
  398.         protoTrace("Error sending T.30 prologue frames");
  399.         continue;
  400.         }
  401.         /*
  402.          * Delay before switching to high speed carrier
  403.          * to send the TCF data.  Note that we use pause
  404.          * instead of +FTS because many modems are slow
  405.          * to return the OK result and this can screw up
  406.          * timing.  Reportedly some modems won't work
  407.          * properly unless they see +FTS before the TCF,
  408.          * but for now we stick with what appears to work
  409.          * the best with the modems we use.
  410.          */
  411.         pause(conf.class1SendTCFDelay);
  412.         if (!sendTCF(params, TCF_DURATION)) {
  413.         if (abortRequested())
  414.             goto done;
  415.         protoTrace("Problem sending TCF data");
  416.         }
  417.         /*
  418.          * Receive response to training.  Acceptable
  419.          * responses are: DIS or DTC (DTC not handled),
  420.          * FTT, or CFR; and also a premature DCN.
  421.          */
  422.         HDLCFrame frame(conf.class1FrameOverhead);
  423.         if (recvFrame(frame, conf.t4Timer)) {
  424.         do {
  425.             switch (frame.getFCF()) {
  426.             case FCF_NSF|FCF_RCVR:
  427.             { u_int nsf = frame.getDataWord(); }
  428.             break;
  429.             case FCF_CSI|FCF_RCVR:
  430.             { fxStr csi; decodeTSI(csi, frame); recvCSI(csi); }
  431.             break;
  432.             }
  433.         } while (frame.moreFrames() && recvFrame(frame, conf.t4Timer));
  434.         }
  435.         if (frame.isOK()) {
  436.         switch (frame.getFCF()) {
  437.         case FCF_CFR|FCF_RCVR:        // training confirmed
  438.             protoTrace("TRAINING succeeded");
  439.             setDataTimeout(60, params.br);
  440.             return (TRUE);
  441.         case FCF_FTT|FCF_RCVR:        // failure to train, retry
  442.             break;
  443.         case FCF_DIS|FCF_RCVR:        // new capabilities, maybe
  444.             { u_int newDIS = frame.getDIS();
  445.               if (newDIS != dis) {
  446.             dis = newDIS;
  447.             params.setFromDIS(dis, frame.getXINFO());
  448.             curcap = NULL;
  449.               }
  450.             }
  451.             return (sendTraining(params, --tries, emsg));
  452.         default:
  453.             if (frame.getFCF() == (FCF_DCN|FCF_RCVR))
  454.             emsg = "RSRPEC error/got DCN";
  455.             else
  456.             emsg = "RSPREC invalid response received";
  457.             goto done;
  458.         }
  459.         }
  460.         // delay to give other side time to reset
  461.         pause(conf.class1TrainingRecovery);
  462.     } while (--t > 0);
  463.     /*
  464.      * Two attempts at the current speed failed, drop
  465.      * the signalling rate to the next lower rate supported
  466.      * by the local & remote sides and try again.
  467.      */
  468.     } while (dropToNextBR(params));
  469. failed:
  470.     emsg = "Failure to train remote modem";
  471. done:
  472.     protoTrace("TRAINING failed");
  473.     return (FALSE);
  474. }
  475.  
  476. /*
  477.  * Select the next lower signalling rate that's
  478.  * acceptable to both local and remote machines.
  479.  */
  480. fxBool
  481. Class1Modem::dropToNextBR(Class2Params& params)
  482. {
  483.     for (;;) {
  484.     if (params.br == BR_2400)
  485.         return (FALSE);
  486.     // get ``best capability'' of modem at this baud rate
  487.     curcap = findBRCapability(--params.br, xmitCaps);
  488.     if (curcap) {
  489.         // hunt for compatibility with remote at this baud rate
  490.         do {
  491.         if (isCapable(curcap->sr, dis))
  492.             return (TRUE);
  493.         curcap--;
  494.         } while (curcap->br == params.br);
  495.     }
  496.     }
  497.     /*NOTREACHED*/
  498. }
  499.  
  500. /*
  501.  * Select the next higher signalling rate that's
  502.  * acceptable to both local and remote machines.
  503.  */
  504. fxBool
  505. Class1Modem::raiseToNextBR(Class2Params& params)
  506. {
  507.     for (;;) {
  508.     if (params.br == BR_14400)    // highest speed
  509.         return (FALSE);
  510.     // get ``best capability'' of modem at this baud rate
  511.     curcap = findBRCapability(++params.br, xmitCaps);
  512.     if (curcap) {
  513.         // hunt for compatibility with remote at this baud rate
  514.         do {
  515.         if (isCapable(curcap->sr, dis))
  516.             return (TRUE);
  517.         curcap--;
  518.         } while (curcap->br == params.br);
  519.     }
  520.     }
  521.     /*NOTREACHED*/
  522. }
  523.  
  524. /*
  525.  * Send data for the current page.
  526.  */
  527. fxBool
  528. Class1Modem::sendPageData(u_char* data, u_int cc, const u_char* bitrev)
  529. {
  530.     beginTimedTransfer();
  531.     fxBool rc = sendClass1Data(data, cc, bitrev, FALSE);
  532.     endTimedTransfer();
  533.     protoTrace("SENT %u bytes of data", cc);
  534.     return rc;
  535. }
  536.  
  537. /*
  538.  * Send RTC to terminate a page.  Note that we pad the
  539.  * RTC with zero fill to "push it out on the wire".  It
  540.  * seems that some Class 1 modems do not immediately
  541.  * send all the data they are presented.
  542.  */
  543. fxBool
  544. Class1Modem::sendRTC(fxBool is2D)
  545. {
  546.     static const u_char RTC1D[9+20] =
  547.     { 0x00,0x10,0x01,0x00,0x10,0x01,0x00,0x10,0x01 };
  548.     static const u_char RTC2D[10+20] =
  549.     { 0x00,0x18,0x00,0xC0,0x06,0x00,0x30,0x01,0x80,0x0C };
  550.     protoTrace("SEND %s RTC", is2D ? "2D" : "1D");
  551.     if (is2D)
  552.     return sendClass1Data(RTC2D, sizeof (RTC2D), frameRev, TRUE);
  553.     else
  554.     return sendClass1Data(RTC1D, sizeof (RTC1D), frameRev, TRUE);
  555. }
  556.  
  557. /*
  558.  * Send a page of data.
  559.  */
  560. fxBool
  561. Class1Modem::sendPage(TIFF* tif, const Class2Params& params, fxStr& emsg)
  562. {
  563.     /*
  564.      * Set high speed carrier & start transfer.  If the
  565.      * negotiated modulation technique includes short
  566.      * training, then we use it here (it's used for all
  567.      * high speed carrier traffic other than the TCF).
  568.      */
  569.     int speed = curcap[HasShortTraining(curcap)].value;
  570.     if (!class1Cmd("TM", speed, AT_CONNECT)) {
  571.     emsg = "Unable to establish message carrier";
  572.     return (FALSE);
  573.     }
  574.     fxBool rc = TRUE;
  575.     protoTrace("SEND begin page");
  576.     if (flowControl == FLOW_XONXOFF)
  577.     setXONXOFF(FLOW_XONXOFF, FLOW_NONE, ACT_FLUSH);
  578.     /*
  579.      * Correct bit order of data if not what modem expects.
  580.      */
  581.     u_short fillorder;
  582.     TIFFGetFieldDefaulted(tif, TIFFTAG_FILLORDER, &fillorder);
  583.     const u_char* bitrev =
  584.     TIFFGetBitRevTable(conf.sendFillOrder != FILLORDER_LSB2MSB);
  585.     u_long* stripbytecount;
  586.     (void) TIFFGetField(tif, TIFFTAG_STRIPBYTECOUNTS, &stripbytecount);
  587.     u_char* fill;
  588.     u_char* eoFill;
  589.     u_long w = 0xffffff;
  590.     u_int minLen = params.minScanlineSize();
  591.     if (minLen > 0) {
  592.     /*
  593.      * Client requires a non-zero min-scanline time.  We
  594.      * comply by zero-padding scanlines that have <minLen
  595.      * bytes of data to send.  To minimize underrun we
  596.      * do this padding in a strip-sized buffer.
  597.      */
  598.     u_long rowsperstrip;
  599.     TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
  600.     if (rowsperstrip == (u_long) -1)
  601.          TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &rowsperstrip);
  602.     fill = new u_char[minLen*rowsperstrip];
  603.     eoFill = fill + minLen*rowsperstrip;
  604.     }
  605.     u_char* fp = fill;
  606.     for (u_int strip = 0; strip < TIFFNumberOfStrips(tif) && rc; strip++) {
  607.     u_int totbytes = (u_int) stripbytecount[strip];
  608.     if (totbytes > 0) {
  609.         u_char* buf = new u_char[totbytes];
  610.         if (TIFFReadRawStrip(tif, strip, buf, totbytes) >= 0) {
  611.         /*
  612.          * Send the strip of data.  This is slightly complicated
  613.          * by the fact that we may have to add zero-fill before the
  614.          * EOL codes to bring the transmit time for each scanline
  615.          * up to the negotiated min-scanline time.
  616.          *
  617.          * Note that we blindly force the data to be in LSB2MSB bit
  618.          * order so that the EOL locating code works (if needed).
  619.          * This may result in two extraneous bit reversals if the
  620.          * modem wants the data in MSB2LSB order, but for now we'll
  621.          * avoid the temptation to optimize.
  622.          */
  623.         if (fillorder != FILLORDER_LSB2MSB)
  624.             TIFFReverseBits(buf, totbytes);
  625.         if (minLen > 0) {
  626.             u_char* bp = buf;
  627.             u_char* ep = buf+totbytes;
  628.             do {
  629.             u_char* bol = bp;
  630.             do {
  631.                 w = (w<<8) | *bp++;
  632.             } while (!EOLcode(w) && bp < ep);
  633.             /*
  634.              * We're either at an EOL code or at the end of data.
  635.              * If necessary, insert zero-fill before the last byte
  636.              * in the EOL code so that we comply with the
  637.              * negotiated min-scanline time.
  638.              */
  639.             u_int lineLen = bp - bol;
  640.             if (fp + fxmax(lineLen, minLen) >= eoFill) {
  641.                 /*
  642.                  * Not enough space for this scanline, flush
  643.                  * the current data and reset the pointer into
  644.                  * the zero fill buffer.
  645.                  */
  646.                 rc = sendPageData(fill, fp-fill, bitrev);
  647.                 fp = fill;
  648.                 if (!rc)            // error writing data
  649.                 break;
  650.             }
  651.             memcpy(fp, bol, lineLen);    // first part of line
  652.             fp += lineLen;
  653.             if (lineLen < minLen) {        // must zero-fill
  654.                 u_int zeroLen = minLen - lineLen;
  655.                 memset(fp-1, 0, zeroLen);    // zero padding
  656.                 fp += zeroLen;
  657.                 fp[-1] = bp[-1];        // last byte in EOL
  658.             }
  659.             } while (bp < ep);
  660.         } else {
  661.             /*
  662.              * No EOL-padding needed, just jam the bytes.
  663.              */
  664.             rc = sendPageData(buf, totbytes, bitrev);
  665.         }
  666.         }
  667.         delete buf;
  668.     }
  669.     }
  670.     if (minLen > 0) {
  671.     /*
  672.      * Flush anything that was not sent above.
  673.      */
  674.     if (fp > fill)
  675.         rc = sendPageData(fill, fp-fill, bitrev);
  676.     delete fill;
  677.     }
  678.     if (rc || abortRequested())
  679.     rc = sendRTC(params.is2D());
  680.     protoTrace("SEND end page");
  681.     if (rc) {
  682.     /*
  683.      * Wait for transmit buffer to empty.
  684.      */
  685.     ATResponse r;
  686.     while ((r = atResponse(rbuf, getDataTimeout())) == AT_OTHER)
  687.         ;
  688.     rc = (r == AT_OK);
  689.     }
  690.     if (flowControl == FLOW_XONXOFF)
  691.     setXONXOFF(FLOW_NONE, FLOW_NONE, ACT_DRAIN);
  692.     if (!rc)
  693.     emsg = "Unspecified Transmit Phase C error";    // XXX
  694.     return (rc);
  695. }
  696.  
  697. /*
  698.  * Send the post-page-message and wait for a response.
  699.  */
  700. fxBool
  701. Class1Modem::sendPPM(u_int ppm, HDLCFrame& mcf, fxStr& emsg)
  702. {
  703.     for (int t = 0; t < 3; t++) {
  704.     tracePPM("SEND send", ppm);
  705.     if (!transmitFrame(ppm|FCF_SNDR)) {
  706.         if (!abortRequested())
  707.         emsg = "Error transmitting post-page message";
  708.         return (FALSE);
  709.     }
  710.     if (recvFrame(mcf, conf.t4Timer))
  711.         return (TRUE);
  712.     }
  713.     emsg = "No response to MPS or EOP repeated 3 tries";
  714.     return (FALSE);
  715. }
  716.  
  717. /*
  718.  * Terminate a send session.
  719.  */
  720. void
  721. Class1Modem::sendEnd()
  722. {
  723.     transmitFrame(FCF_DCN|FCF_SNDR);        // disconnect
  724.     setInputBuffering(TRUE);
  725. }
  726.